

因为react navigation对不使用expo的应用也能行,所以接下来学习react navigation。文档:https://reactnavigation.org/
1、创建项目npx create-expo-app@latest RNNavigation --template blank,这个命令会创建一个没有expo router的项目,方便我们学习react navigation。
2、安装react navigation:npm install @react-navigation/native
3、安装依赖:npx expo install react-native-screens react-native-safe-area-context
4、在入口文件(App.js / App.tsx)启用 NavigationContainer
x1// App.js23import { NavigationContainer } from "@react-navigation/native";45export default function App() {6 return <NavigationContainer>{/* Rest of your app code */}</NavigationContainer>;7}接下来,就可以在App里面写导航相关的代码了。
React Navigation 的 Navigator 大概分成四大类:
1️⃣ Stack Navigator(最常用、页面跳转)
就像浏览器前进/后退、App 页面跳转一样:
xxxxxxxxxx11Home → List → Detail → Settings每个页面像“一张纸”压在另一张上面。
⭐ 特点
- 有“入栈 / 出栈”机制(push/pop)
- 自带标题栏(header)
- 支持动画(iOS 推入动画 / Android 淡入)
- 世界上 80% 的 App 页面跳转用 Stack
⭐ 适合场景
- 详情页
- 登录流程
- 配置页面
- 多级页面跳转
⭐ 典型用法
xxxxxxxxxx11const Stack = createNativeStackNavigator();2️⃣ Tab Navigator(底部导航 ⁄ 顶部导航)
底部菜单栏:
xxxxxxxxxx11[Home] [Explore] [Profile]用户点击 Tab 切换页面。
⭐ 特点
- 永远显示在底部(或顶部)
- 可以为每个 Tab 配置图标
- 内部通常嵌套 Stack(非常常见)
⭐ 适合场景
- App 主体结构
- Home、Search、Notifications、Profile 等一级功能
⭐ 用法
xxxxxxxxxx11const Tab = createBottomTabNavigator();3️⃣ Drawer Navigator(侧边抽屉导航)
左侧滑出(或右侧)的菜单:
xxxxxxxxxx11|≡| → 抽屉滑出⭐ 特点
- 左滑出现,常做“设置/个人中心/管理项”
- 类似微信的“我”、Google 的侧边栏
- 支持自定义抽屉内容
⭐ 适合场景
- 内容很多但不需要一直显示的菜单
- 管理类、设置类应用
⭐ 用法
xxxxxxxxxx11const Drawer = createDrawerNavigator();4️⃣ Material 系导航(根据 UI 规范设计)
如果你想做更“安卓风格”的 UI,可以用:
🔹 Material Bottom Tabs
xxxxxxxxxx11import { createMaterialBottomTabNavigator } from '@react-navigation/material-bottom-tabs';🔹 Material Top Tabs
xxxxxxxxxx11import { createMaterialTopTabNavigator } from '@react-navigation/material-top-tabs';⭐ 特点
- 使用 Material Design 风格
- Android 风格更强
- 更丰富的交互(滑动、波纹效果)
⭐ 适合场景
- 想让 UI 更接近 Google 原生设计时
🧩 那这些 Navigator 应该怎么组合?
几乎所有大型 RN 应用结构都是:
xxxxxxxxxx61RootStack2├── AuthStack(未登录)3└── AppTabs(登录后)4├── HomeStack5├── ExploreStack6└── ProfileStack也就是说:
⭐ 顶层是 Stack
因为你需要处理:
- 首次进入
- 登录页
- 主应用页
- 404 / Modal 等
⭐ Tabs 放在 Stack 里
因为 Tab 是“主骨架”。
⭐ Drawer 也通常放在 Stack 里
因为 Drawer 控制行为通常独立。
🎯 什么时候选哪种?
📌 想“页面跳转” → Stack
📌 想“底部切换功能” → Tabs
📌 想“滑出菜单” → Drawer
📌 想“安卓风格 Tab(顶部/底部)” → Material 系 Navigator
🔥 最常见的实际用法(强烈推荐)
99% 项目这样写:
xxxxxxxxxx71NavigationContainer2└── RootStack3├── LoginStack4└── MainTabs5├── HomeStack6├── ExploreStack7└── ProfileStack这是大厂 RN 项目的标准结构。
Stack Navigator(堆栈导航)模拟的是 iOS / Android 原生的页面跳转方式:

Stack Navigation有两种,一种是Stack Navigator,另一种是Native Stack Navigator。课程中老师只讲解Native Stack Navigator,参考文档:https://reactnavigation.org/docs/native-stack-navigator
安装依赖:npm install @react-navigation/native-stack

🧱 Stack Navigator 组成部分
一个 Stack Navigator 有三个核心角色:
xxxxxxxxxx171// App.js23import { NavigationContainer } from "@react-navigation/native";4import { createNativeStackNavigator } from "@react-navigation/native-stack";56const Stack = createNativeStackNavigator();78export default function App() {9 return (10 <NavigationContainer>11 <Stack.Navigator>12 {/* 定义了页面之后,需要在这里使用Stack.Screen来指定页面 */}13 {/* <Stack.Screen name="Home" /> */}14 </Stack.Navigator>15 </NavigationContainer>16 );17}Stack.Screen核心属性:
| 属性 | 类型 | 描述 |
|---|---|---|
name | string | 必需。 为此屏幕定义的唯一路由名称。您在导航时(例如使用 navigation.navigate('Home'))将使用此名称。 |
component | React Component | 必需。 当此屏幕成为焦点时将渲染的 React 组件。此组件会自动接收 navigation 和 route props。 |
options | object | 非必需。用于配置此屏幕的外观和行为,例如导航栏的标题、样式、按钮等。 |
options属性
| 选项 (常用) | 类型 | 描述 |
|---|---|---|
title | string | 设置导航栏的标题文字。 |
headerShown | boolean | 设置是否显示导航栏。默认是 true。 |
headerStyle | object | 设置导航栏(头部)的样式,例如背景颜色。 |
headerTitleStyle | object | 设置导航栏标题文本的样式。 |
headerTintColor | string | 设置导航栏按钮和标题的颜色。 |
headerRight | (props) => React Node | 渲染导航栏右侧的组件(例如按钮)。 |
headerLeft | (props) => React Node | 渲染导航栏左侧的组件。 |
presentation | string | 仅在 @react-navigation/native-stack 中:控制屏幕出现的方式(如 modal、card、transparentModal 等)。 |
定义两个相似的页面HomeScreen.js和AboutScreen.js,这里只展示HomeScreen的代码。
xxxxxxxxxx231// screens/HomeScreen.js23import { Text, View, StyleSheet } from "react-native";45export default function HomeScreen() {6 return (7 <View style={styles.container}>8 <Text style={styles.text}>Home Screen</Text>9 </View>10 );11}12const styles = StyleSheet.create({13 container: {14 flex: 1,15 alignItems: "center",16 justifyContent: "center",17 },18 text: {19 fontSize: 24,20 fontWeight: "bold",21 marginBottom: 16,22 },23});xxxxxxxxxx181import { NavigationContainer } from "@react-navigation/native";2import { createNativeStackNavigator } from "@react-navigation/native-stack";3import HomeScreen from "./screens/HomeScreen";4import AboutScreen from "./screens/AboutScreen";56const Stack = createNativeStackNavigator();78export default function App() {9 return (10 <NavigationContainer>11 <Stack.Navigator>12 {/* 定义了页面之后,需要在这里使用Stack.Screen来指定页面 */}13 <Stack.Screen name="Home" component={HomeScreen} />14 <Stack.Screen name="About" component={AboutScreen} />15 </Stack.Navigator>16 </NavigationContainer>17 );18}查看效果:
可以看到,只展示了HomeScreen页面,那页面之间怎么跳转呢?下节课会讲到。
可以通过navigation prop或者useNavigation()这个hook来实现页面之间的跳转。
在 Stack Navigator 中,只要一个组件是作为 Stack.Screen 的 component 属性注册的,它就会自动接收到 navigation 和 route 这两个 props。
使用navigation的navigate方法,进行跳转。

可以看到,从Home跳转到了About页面,同时上面还有一个返回按钮。


| 特性 | navigation Prop | useNavigation() Hook |
|---|---|---|
| 获取方式 | 作为参数 { navigation, route } 传入组件。 | 通过 const navigation = useNavigation(); 调用。 |
| 适用组件 | 屏幕组件 (Screen Component):即直接在 <Stack.Screen component={...}> 中注册的组件。 | 任何组件:屏幕组件或嵌套在屏幕内部的子组件 (Child Component)。 |
| 可访问性 | 只能在作为屏幕注册的组件内部访问。 | 可以在组件树中的任何地方访问(只要它被包裹在导航容器内)。 |
| 代码简洁度 | 略微分散,需要解构 props。 | 独立且清晰,但在非屏幕组件中是唯一选择。 |
| 推荐原则 | 如果组件是直接注册的屏幕,这是标准方式,性能开销最小。 | 如果组件是通用或嵌套的子组件,并且不知道/不关心它是否是屏幕。 |
在Screens之间传递数据。
在调用 navigation.navigate() 或 navigation.push() 时,将数据作为第二个参数的对象传递。在目标屏幕组件中,通过 route.params 访问数据。


效果:

怎么在About里面向Home传递数据呢?如果是手动触发,那么还是可以在navigation.navigate的第二个参数里面传递数据,然后Home里面使用route来接收。
但如果是nav栏的返回按钮触发的返回呢?这个还能生效吗?估计不能,这时候就需要使用第三方状态管理库了。
Stack.Screen的options属性:
| 选项 (常用) | 类型 | 描述 |
|---|---|---|
title | string | 设置导航栏的标题文字。 |
headerShown | boolean | 设置是否显示导航栏。默认是 true。 |
headerStyle | object | 设置导航栏(头部)的样式,例如背景颜色。 |
headerTitleStyle | object | 设置导航栏标题文本的样式。 |
headerTintColor | string | 设置导航栏按钮和标题的颜色。 |
headerRight | (props) => React Node | 渲染导航栏右侧的组件(例如按钮)。 |
headerLeft | (props) => React Node | 渲染导航栏左侧的组件。 |
presentation | string | 仅在 @react-navigation/native-stack 中:控制屏幕出现的方式(如 modal、card、transparentModal 等)。 |
contentStyle | object | 设置屏幕的背景颜色 |

效果:

如果想设置所有页面的nav和content的样式,可以在Stack.Navigator上设置screenOptions属性:

可以看到About页面并没有设置nav和content的样式,也成功有了样式。

options 属性的函数形式 (推荐)在 Stack.Screen 的 options 属性中传入一个函数,该函数会接收到包含当前路由信息的对象。
xxxxxxxxxx91// App.js23<Stack.Screen4 name="About"5 component={AboutScreen}6 options={({ route }) => {7 title: route.params?.name || "";8 }}9/>可以看到,跳转到About页面时,nav栏的标题变为了传递的参数。

navigation.setOptions() 方法 (最灵活)当您需要根据屏幕内部的异步数据或用户交互(例如,用户在表单中输入内容、数据加载完成)来改变导航栏时,您需要在组件内部调用 navigation.setOptions() 方法。

接下来关于导航的内容,老师讲的都非常快,很多属性都是一笔带过,这个了解一下即可,现在流行expo router,就使用它即可。
Drawer Navigation 是 React Native 中非常常用的一种导航模式,通常用于提供应用主功能区域的入口,或放置不太常用的设置和配置项。它以一个从屏幕边缘滑入(通常是左侧)的侧边面板的形式呈现。参考文档:https://reactnavigation.org/docs/drawer-navigator

安装依赖:npm install @react-navigation/drawer, npx expo install react-native-gesture-handler react-native-reanimated react-native-worklets
将原来的App.js改为AppStack.js,然后新建一个App.js文件。
xxxxxxxxxx201// App.js23import "react-native-gesture-handler";4import { NavigationContainer } from "@react-navigation/native";5import { createDrawerNavigator } from "@react-navigation/drawer";6import DashboardScreen from "./screens/DashboardScreen";7import SettingScreen from "./screens/SettingScreen";89const Drawer = createDrawerNavigator();1011export default function App() {12 return (13 <NavigationContainer>14 <Drawer.Navigator>15 <Drawer.Screen name="Dashboard" component={DashboardScreen} />16 <Drawer.Screen name="Settings" component={SettingScreen} />17 </Drawer.Navigator>18 </NavigationContainer>19 );20}创建两个相似的页面:
xxxxxxxxxx261// DashboardScreen.js23import { View, Text, StyleSheet } from "react-native";45const DashboardScreen = () => {6 return (7 <View style={styles.container}>8 <Text style={styles.text}>Dashboard Screen</Text>9 </View>10 );11};1213export default DashboardScreen;1415const styles = StyleSheet.create({16 container: {17 flex: 1,18 alignItems: "center",19 justifyContent: "center",20 },21 text: {22 fontSize: 24,23 fontWeight: "bold",24 marginBottom: 16,25 },26});效果:

屏幕导航栏配置 (Header/Screen Options)
| 属性名 | 类型 | 描述 |
|---|---|---|
title | string | 设置 Header 中央显示的标题文本。 |
headerShown | boolean | 是否显示 Header(导航栏)。默认 true。 |
headerStyle | object | Header 容器的样式,常用于设置 backgroundColor。 |
headerTintColor | string | Header 上的按钮和标题的颜色。 |
headerLeft | (props) => React Node | 渲染 Header 左侧的自定义组件。在 Drawer 导航器中,通常这里会放置抽屉开关按钮。 |
headerRight | (props) => React Node | 渲染 Header 右侧的自定义组件。 |
headerTitleStyle | object | 标题文本的样式。 |
抽屉菜单项配置 (Drawer Item Appearance)
| 属性名 | 类型 | 默认值 | 描述 |
|---|---|---|---|
drawerLabel | string 或 (props) => React Node | 路由的 name | 在抽屉菜单中显示的文本标签。如果为函数,可以返回自定义组件。 |
drawerIcon | (props) => React Node | undefined | 在抽屉菜单项旁边显示的图标组件。接收 { focused, color, size } 属性。 |
drawerItemStyle | object | undefined | 应用于抽屉菜单项整个容器的样式。 |
drawerLabelStyle | object | undefined | 应用于抽屉菜单项文本标签的样式。 |
drawerActiveTintColor | string | 平台默认色 | 抽屉菜单项处于 活动/焦点 状态时,图标和文本的颜色。 |
drawerInactiveTintColor | string | 平台默认色 | 抽屉菜单项处于 非活动 状态时,图标和文本的颜色。 |
drawerActiveBackgroundColor | string | 透明 | 抽屉菜单项处于 活动/焦点 状态时,背景的颜色。 |
drawerInactiveBackgroundColor | string | 透明 | 抽屉菜单项处于 非活动 状态时,背景的颜色。 |
swipeEnabled | boolean | true | 是否允许通过屏幕边缘手势滑动来打开/关闭抽屉。 |

安装npm install @react-navigation/bottom-tabs
将App.js文件名改为AppDrawer.js,然后创建App.js文件。
xxxxxxxxxx211// App.js23import { NavigationContainer } from "@react-navigation/native";4import { createBottomTabNavigator } from "@react-navigation/bottom-tabs";5import HomeScreen from "./screens/HomeScreen";6import DashboardScreen from "./screens/DashboardScreen";7import SettingScreen from "./screens/SettingScreen";89const Tab = createBottomTabNavigator();1011export default function App() {12 return (13 <NavigationContainer>14 <Tab.Navigator>15 <Tab.Screen name="Home" component={HomeScreen} />16 <Tab.Screen name="Dashboard" component={DashboardScreen} />17 <Tab.Screen name="Setting" component={SettingScreen} />18 </Tab.Navigator>19 </NavigationContainer>20 );21}

标签栏条目配置 (Tab Bar Item Appearance)
| 属性名 | 类型 | 适用 | 描述 |
|---|---|---|---|
tabBarLabel | string 或 (props) => React Node | Both | 标签栏中显示的文本标签。如果为函数,可实现动态渲染或自定义组件。 |
tabBarIcon | (props) => React Node | Both | 标签栏中显示的图标组件。接收 { focused, color, size } 属性,用于根据焦点状态切换图标。 |
tabBarBadge | string 或 number 或 boolean | Bottom | 在标签栏图标上方显示的小红点或数字(如未读消息数量)。 |
tabBarAccessibilityLabel | string | Both | 供屏幕阅读器使用的可访问性标签。 |
tabBarTestID | string | Both | 用于测试的 ID。 |
tabBarButton | (props) => React Node | Both | 用于完全自定义整个标签项组件(包括容器和点击行为)。 |
tabBarShowLabel | boolean | Both | 是否显示标签文本。如果为 false,则只显示图标。 |
tabBarActiveTintColor | string | Both | 标签项处于 活动/焦点 状态时,图标和文本的颜色。 |
tabBarInactiveTintColor | string | Both | 标签项处于 非活动 状态时,图标和文本的颜色。 |
屏幕/导航栏配置 (Screen & Header Options)
| 属性名 | 类型 | 适用 | 描述 |
|---|---|---|---|
title | string | Both | 设置 Header 中央显示的标题文本。 |
headerShown | boolean | Both | 是否显示 Header(导航栏)。如果 Tab 嵌套在 Stack 中,通常需要在 Stack 导航器中配置。 |
lazy | boolean | Bottom | 仅 Bottom Tab。 是否延迟加载此屏幕组件,直到用户第一次访问它。默认 true。 |
unmountOnBlur | boolean | Both | 屏幕失去焦点时是否卸载(Unmount)该组件,下次访问时重新渲染。 |
freezeOnBlur | boolean | Both | 屏幕失去焦点时是否停止渲染和事件处理,以优化性能。 |
contentStyle | object | Both | 设置屏幕内容区域的样式(例如背景色)。 |

核心原则:
Stack Navigator 应该作为容器,包裹住 Tab Navigator 或 Drawer Navigator。
这是因为 Tab 和 Drawer 导航器通常代表应用的主要结构,而 Stack Navigator 负责处理每个主要部分的历史记录和屏幕之间的过渡效果。
这是最常见的模式。应用底部有一个固定的 Tab Bar,每个 Tab 内部管理自己的导航历史。
结构图
实现方式:
Tab.Screen 的 component 中,嵌套一个独立的 Stack Navigator。Home Stack 负责 Home 到 HomeDetails 的跳转)。示例代码:
xxxxxxxxxx351// 1. 定义每个 Tab 内部的 Stack 导航器2function HomeStackScreen() {3 return (4 <Stack.Navigator>5 <Stack.Screen name="Home" component={HomeScreen} />6 <Stack.Screen name="HomeDetails" component={HomeDetailsScreen} />7 </Stack.Navigator>8 );9}1011// 2. 定义 Tab Navigator 作为应用主体12function MainTabs() {13 return (14 <Tab.Navigator>15 <Tab.Screen name="HomeTab" component={HomeStackScreen} />16 <Tab.Screen name="SettingsTab" component={SettingsScreen} />17 </Tab.Navigator>18 );19}2021// 3. 定义最外层 Stack 导航器(用于 Modal 或 Login)22function RootNavigator() {23 return (24 <Stack.Navigator screenOptions={{ headerShown: false }}>25 {/* 登录/注册流程(假设用户未登录) */}26 <Stack.Screen name="Auth" component={AuthStackScreen} />27 28 {/* 主应用内容(用户已登录) */}29 <Stack.Screen name="MainApp" component={MainTabs} /> 30 31 {/* 全局模态框,例如全屏通知 */}32 <Stack.Screen name="GlobalModal" component={ModalScreen} options={{ presentation: 'modal' }} />33 </Stack.Navigator>34 );35}经验法则: